%     FASTENER DOCTOR - программа для лечения и конвертации крепежа
%     Copyright (C) 2018  Михаил Козлов
%     Сайт проекта: <http://www.fastenerdoctor.ru/>
%     Адрес электронной почты для связи с разработчиком:
%     <doctor.fastener@gmail.com>
% 
%     Эта программа является свободным программным обеспечением: Вы можете
%     распространять ее и/или изменять, соблюдая условия Универсальной общественной
%     лицензии GNU, опубликованной Фондом свободного программного обеспечения,
%     либо редакции 3, либо (на Ваше усмотрение) любой редакции, выпущенной позже.
% 
%     Эта программа распространяется в надежде на то, что она окажется полезной,
%     но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, включая даже подразумеваемую гарантию ТОВАРНОЙ ПРИГОДНОСТИ,
%     либо ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Ознакомьтесь с Универсальной общественной
%     лицензией GNU для получения более подробной информации.
% 
%     Вы должны были получить копию Универсальной общественной лицензии GNU
%     вместе с этой программой. Если Вы ее не получили, то перейдите по адресу:
%     <http://www.gnu.org/licenses/>.
% 
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
% 
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
%     GNU General Public License for more details.
% 
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <https://www.gnu.org/licenses/>.

function Convert_Bar_To_Rutman(Fastener_Index, RutFast_Axial_Constraint)

global ErrCode;

global DB_ELEMENTS;
global DB_PSETS;

global AT_ELEMENTS;
global AT_PSETS;

global DB_FASTENERS;

global db_Next_Coord_Number;
global db_Next_Node_Number;
global db_Next_Element_Number;
global db_Next_MPC_Number;

% Исправление офсетов точек смятия
[temp_counter_1, temp_counter_2, temp_counter_3] = Repair_BarFast_Offsets(Fastener_Index); %#ok<ASGLU>

if (ErrCode < 0)
    return;
end

% --- Создание общей СК болта ---

% Получение оси болта
[Axis_Point_1, Axis_Point_2, Axis_vector] = Get_Fastener_Axis(Fastener_Index);

if (ErrCode < 0)
    return;
end

% Индекс яруса со стороны головки болта
Head_Layer = 1;

% Получение точек для расчета направления
Point_1 = Get_Plate_Midsurf_Point(Fastener_Index, Head_Layer, Axis_Point_1, Axis_Point_2, Axis_vector);

if (ErrCode < 0)
    return;
end

Point_2 = Get_Plate_Midsurf_Point(Fastener_Index, DB_FASTENERS{Fastener_Index}.N_layers-Head_Layer+1, Axis_Point_1, Axis_Point_2, Axis_vector);

if (ErrCode < 0)
    return;
end

if (Equiv_Check_Cube(Point_1, Point_2))
    fprintf (1, '\nОшибка: нулевое расстояние между крайними срединными точками в болте Рутмана с номером %i !\n', Fastener_Index);
    ErrCode = -1;
    return;
end

Midsurface_Point = Point_1;

% Получение знака
Sign = sign(dot(Point_1 - Point_2, Axis_vector));

% Толщина текущего яруса
Plate_Thickness = Get_Plate_Thickness(Fastener_Index, Head_Layer, Axis_Point_1, Axis_Point_2);

if (ErrCode < 0)
    return;
end

% Координаты начала системы координат
Origin = Midsurface_Point + Plate_Thickness/2 * Axis_vector * Sign;

% Координаты точки на оси 3
Point_on_axis_3 = Midsurface_Point + Plate_Thickness * Axis_vector * Sign;

% Получение направления оси X общей СК болта
[Ref_Dir_Origin, Ref_Dir_Vector] = Get_Fast_Coord_X_Direction(Fastener_Index, Head_Layer, Axis_Point_1, Axis_Point_2, Axis_vector);

if (ErrCode < 0)
    return;
end

% Координаты точки в плоскости 13
Point_on_plane_13 = Ref_Dir_Origin + Ref_Dir_Vector;

% Создание системы координат
Append_To_Output(PCL_Coord_Create_Rect_3P(Origin, Point_on_axis_3, Point_on_plane_13));
General_Coord_ID = DB_Coord_Create_Rect_3P(Origin, Point_on_axis_3, Point_on_plane_13);
db_Next_Coord_Number = db_Next_Coord_Number + 1;

if (ErrCode < 0)
    return;
end

% --- Создание двух новых узлов ---

% Создание первого нового узла
Reference_Coord = 0;
Analysis_Coord = 0;
Location = DB_FASTENERS{Fastener_Index}.Shank_nodes(1);

Append_To_Output(PCL_Node_Create(Reference_Coord, Analysis_Coord, Location));
New_node_1_ID = DB_Node_Create(Reference_Coord, Analysis_Coord, Location);
db_Next_Node_Number = db_Next_Node_Number + 1;

if (ErrCode < 0)
    return;
end

% Создание второго нового узла
Reference_Coord = 0;
Analysis_Coord = 0;
Location = DB_FASTENERS{Fastener_Index}.Shank_nodes(DB_FASTENERS{Fastener_Index}.N_layers);

Append_To_Output(PCL_Node_Create(Reference_Coord, Analysis_Coord, Location));
New_node_2_ID = DB_Node_Create(Reference_Coord, Analysis_Coord, Location);
db_Next_Node_Number = db_Next_Node_Number + 1;

if (ErrCode < 0)
    return;
end

% --- Создание двух новых элементов ---

% Создание первого нового элемента
Node_1 = New_node_1_ID;
Node_2 = DB_FASTENERS{Fastener_Index}.Shank_nodes(1);

Append_To_Output(PCL_Elm_Create_Bar(Node_1, Node_2));
New_Element_1_ID = DB_Elm_Create_Bar(Node_1, Node_2);
db_Next_Element_Number = db_Next_Element_Number + 1;

if (ErrCode < 0)
    return;
end

% Создание второго нового элемента
Node_1 = DB_FASTENERS{Fastener_Index}.Shank_nodes(DB_FASTENERS{Fastener_Index}.N_layers);
Node_2 = New_node_2_ID;

Append_To_Output(PCL_Elm_Create_Bar(Node_1, Node_2));
New_Element_2_ID = DB_Elm_Create_Bar(Node_1, Node_2);
db_Next_Element_Number = db_Next_Element_Number + 1;

if (ErrCode < 0)
    return;
end

% Привязка элементов к property set
Pset_ID = DB_ELEMENTS{AT_ELEMENTS(DB_FASTENERS{Fastener_Index}.Shank_elements(1))}.Prop_ID;
Pset_Name = DB_PSETS{AT_PSETS(Pset_ID)}.Patran_name;

if (~isempty(Pset_Name))
    
    % Привязываем два новых элемента к существующему property set
    Append_To_Output(PCL_Elm_Modify_Pset([New_Element_1_ID; New_Element_2_ID], Pset_Name));
    DB_Elm_Modify_Pset([New_Element_1_ID; New_Element_2_ID], Pset_ID);

    if (ErrCode < 0)
        return;
    end
    
else
    
    fprintf (1, '\nОшибка функции Convert_Bar_To_Rutman: пустое имя property set с номером %i !\n', Pset_ID);
    fprintf (1, 'ВНИМАНИЕ! Если эта ошибка возникла, то обязательно сообщите о ней разработчику!\n');
    fprintf (1, 'Обходной путь для решения данной проблемы следующий:\n');
    fprintf (1, 'Убедитесь, что имя property set, к которому привязан балочный элемент с номером %i, присутствует в bdf файле.\n', DB_FASTENERS{Fastener_Index}.Shank_elements(1));
    fprintf (1, 'Оно должно задаваться в виде комментация перед карточкой соответствующего property set.\n');
    ErrCode = -1;
    return;

end

% Внесение изменений в базу данных крепежа
Old_shank_nodes = DB_FASTENERS{Fastener_Index}.Shank_nodes;
DB_FASTENERS{Fastener_Index}.Shank_nodes = [New_node_1_ID; DB_FASTENERS{Fastener_Index}.Shank_nodes; New_node_2_ID];
DB_FASTENERS{Fastener_Index}.Shank_elements = [New_Element_1_ID; DB_FASTENERS{Fastener_Index}.Shank_elements; New_Element_2_ID];

% --- Отсоединение стержня болта ---

% Создание новых узлов стержня болта
New_nodes = zeros(DB_FASTENERS{Fastener_Index}.N_layers,1);

for j=1:DB_FASTENERS{Fastener_Index}.N_layers
    
    Reference_Coord = 0;
    Analysis_Coord = 0;
    Location = Old_shank_nodes(j);

    Append_To_Output(PCL_Node_Create(Reference_Coord, Analysis_Coord, Location));
    New_nodes(j) = DB_Node_Create(Reference_Coord, Analysis_Coord, Location);
    db_Next_Node_Number = db_Next_Node_Number + 1;

    if (ErrCode < 0)
        return;
    end
    
end

% Отсоединение стержня болта от старых узлов
Element_list = DB_FASTENERS{Fastener_Index}.Shank_elements;
Node_list = Old_shank_nodes;
Target_Node_list = New_nodes;

Append_To_Output(PCL_Elm_Modify_Conn(Element_list, Node_list, Target_Node_list));
DB_Elm_Modify_Conn(Element_list, Node_list, Target_Node_list);

if (ErrCode < 0)
    return;
end

% Внесение изменений в базу данных крепежа
DB_FASTENERS{Fastener_Index}.Additional_nodes = zeros(DB_FASTENERS{Fastener_Index}.N_layers,1);

for j=1:DB_FASTENERS{Fastener_Index}.N_layers
    
    DB_FASTENERS{Fastener_Index}.Shank_nodes(j+1) = New_nodes(j);
    DB_FASTENERS{Fastener_Index}.Additional_nodes(j) = Old_shank_nodes(j);
    
end

% --- Изменение систем координат узлов ---

Node_list = [DB_FASTENERS{Fastener_Index}.Shank_nodes; DB_FASTENERS{Fastener_Index}.Additional_nodes; DB_FASTENERS{Fastener_Index}.Joint_nodes];

New_Reference_Coord = General_Coord_ID;
New_Analysis_Coord = General_Coord_ID;

Append_To_Output(PCL_Node_Edit_Coord(Node_list, New_Reference_Coord, New_Analysis_Coord));
DB_Node_Edit_Coord(Node_list, New_Reference_Coord, New_Analysis_Coord);

if (ErrCode < 0)
    return;
end

% --- Расстановка RBAR ---

% Выделение памяти
DB_FASTENERS{Fastener_Index}.RBAR_MPCs = zeros(DB_FASTENERS{Fastener_Index}.N_layers + 1,1);

% Три вида степеней свободы
switch RutFast_Axial_Constraint
    case 'RBAR_DOF'
        DOF_Type_1 = 3456;
    case 'USER_BC'
        DOF_Type_1 = 345;
    otherwise
        fprintf (1, '\nОшибка функции Convert_Bar_To_Rutman: недопустимое значение параметра RutFast_Axial_Constraint [%s] !\n', RutFast_Axial_Constraint);
        ErrCode = -1;
        return;
end

DOF_Type_2 = 345;
DOF_Type_3 = 45;

% Создание RBAR 1 типа
Ind_Node = DB_FASTENERS{Fastener_Index}.Shank_nodes(1);
Dep_Node = DB_FASTENERS{Fastener_Index}.Additional_nodes(1);
Dep_DOFs = DOF_Type_1;

Append_To_Output(PCL_MPC_Create_RBAR(Ind_Node, Dep_Node, Dep_DOFs));
DB_FASTENERS{Fastener_Index}.RBAR_MPCs(1) = DB_MPC_Create_RBAR(Ind_Node, Dep_Node, Dep_DOFs);
db_Next_MPC_Number = db_Next_MPC_Number + 1;

if (ErrCode < 0)
    return;
end

% Создание RBAR 2 типа
for i=2:DB_FASTENERS{Fastener_Index}.N_layers
    
    Ind_Node = DB_FASTENERS{Fastener_Index}.Additional_nodes(i-1);
    Dep_Node = DB_FASTENERS{Fastener_Index}.Additional_nodes(i);
    Dep_DOFs = DOF_Type_2;

    Append_To_Output(PCL_MPC_Create_RBAR(Ind_Node, Dep_Node, Dep_DOFs));
    DB_FASTENERS{Fastener_Index}.RBAR_MPCs(i) = DB_MPC_Create_RBAR(Ind_Node, Dep_Node, Dep_DOFs);
    db_Next_MPC_Number = db_Next_MPC_Number + 1;

    if (ErrCode < 0)
        return;
    end
    
end

% Создание RBAR 3 типа
Ind_Node = DB_FASTENERS{Fastener_Index}.Additional_nodes(DB_FASTENERS{Fastener_Index}.N_layers);
Dep_Node = DB_FASTENERS{Fastener_Index}.Shank_nodes(DB_FASTENERS{Fastener_Index}.N_layers + 2);
Dep_DOFs = DOF_Type_3;

Append_To_Output(PCL_MPC_Create_RBAR(Ind_Node, Dep_Node, Dep_DOFs));
DB_FASTENERS{Fastener_Index}.RBAR_MPCs(DB_FASTENERS{Fastener_Index}.N_layers + 1) = DB_MPC_Create_RBAR(Ind_Node, Dep_Node, Dep_DOFs);
db_Next_MPC_Number = db_Next_MPC_Number + 1;

if (ErrCode < 0)
    return;
end

% Внесение изменений в базу данных крепежа
DB_FASTENERS{Fastener_Index}.Head_MPC_Index = 1;

% --- Расстановка BUSH-элементов ---

% Выделение памяти
DB_FASTENERS{Fastener_Index}.Bush_elements = cell(DB_FASTENERS{Fastener_Index}.N_layers,1);

% Создание элементов
for j=1:DB_FASTENERS{Fastener_Index}.N_layers
    
    Node_1 = DB_FASTENERS{Fastener_Index}.Additional_nodes(j);
    Node_2 = DB_FASTENERS{Fastener_Index}.Shank_nodes(j+1);

    Append_To_Output(PCL_Elm_Create_Bar(Node_1, Node_2));
    DB_FASTENERS{Fastener_Index}.Bush_elements{j} = DB_Elm_Create_Bar(Node_1, Node_2);
    db_Next_Element_Number = db_Next_Element_Number + 1;

    if (ErrCode < 0)
        return;
    end
    
end

% Создание property set
for j=1:DB_FASTENERS{Fastener_Index}.N_layers
    
    % Получение имени нового property set с префиксом FD
    New_Pset_Name = Get_Next_FD_PSet_Name();

    % Создание нового property set с префиксом FD
    Append_To_Output(PCL_PSet_Create_Bush(New_Pset_Name, General_Coord_ID, 0, 0, 0, 0, 0, 0, DB_FASTENERS{Fastener_Index}.Bush_elements{j}(1)));
    Created_PSet_ID = DB_PSet_Create_Bush(New_Pset_Name, General_Coord_ID, 0, 0, 0, 0, 0, 0, DB_FASTENERS{Fastener_Index}.Bush_elements{j}(1)); %#ok<NASGU>

    if (ErrCode < 0)
        return;
    end
    
end

% --- Заполнение топологии крепежа ---

DB_FASTENERS{Fastener_Index}.topology = 'rutman_fastener';

% --- Исправление болта ---

% Исправление офсетов точек смятия (делается из-за крайних узлов стержня болта)
[temp_counter_1, temp_counter_2, temp_counter_3] = Repair_RutFast_Offsets(Fastener_Index); %#ok<ASGLU>

if (ErrCode < 0)
    return;
end

% Исправление BUSH-элементов
[temp_counter_1, temp_counter_2, temp_counter_3, temp_counter_4, temp_counter_5] = Repair_RutFast_Bush(Fastener_Index); %#ok<ASGLU>

if (ErrCode < 0)
    return;
end
